<?php


namespace app\app\controller;

require ROOT_PATH . 'aliyun-oss-php-sdk-2.4.0/autoload.php';

use app\common\controller\All;
use app\common\util\ImgCompressor;
use OSS\Model\ObjectInfo;
use OSS\Model\PrefixInfo;
use OSS\OssClient;
use OSS\Core\OssException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

use think\db\exception\PDOException;

use function db;

class Bjm3u8 extends All
{
    public $accessKeyId = "LTAI4G5dGuDFgvzjm8wSqReQ";
    public $accessKeySecret = "JSyjc0KA3o1aesHivcuDUZoQicXJJe";
// Endpoint以杭州为例，其它Region请按实际情况填写。
    public $endpoint = "http://oss-cn-zhangjiakou.aliyuncs.com";
// 存储空间名称
    public $bucket = "zjkhch";

    public $m3u8Url = "http://dawenjian.aojiasen.cn/";
    public $ossPathPre = 'bajiecache/';
    public $ossClient;
    public $cachePath = 'upload/bajiem3u8Cache';//相对根目录的本地缓存路径
    public $needDownloadTs = false;//是否下载ts
    public $downloadTsNumbers = 0;//下载文件数据
    public $offsetTsNumbers = 1;//下载文件数据
    public $offsetDuration = 10;//10秒
    public $canUploadToOss = true;//上传到oss

    public function __construct()
    {
        parent::__construct();
        //安全检查
        $host = request()->host();
        selfDump('当前访问的域名是', $host);
//            if ($host !== 'video.acorntimes.com' && strpos($host, '127') !== 0 && strpos($host, '192.168.199') !== 0) {
//                $this->error('您访问数据不存在！');
//            }
        $this->ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
    }

    public function doJob()
    {
        //确保每次启动后不会出现问题
        ignore_user_abort(true);
        set_time_limit(0);
        try {
            //处理新增视频
            $this->dealNewVod();
            //处理缓存任务列表
            $this->getUpdateVodList();
            //根据job表进行工作
            $this->dealUpdateVodList();

            //删除重复数据
            $this->deleteRepeatJuji();
//            $this->downloadPic();
        } catch (PDOException $e) {
            selfDump('拦截到异常信息：', $e->getMessage());
            selfDump('异常调用栈：', $e->getTrace());
        }
    }

    /**
     * 用于处理影音要完善的信息
     */
    public function dealNewVod()
    {

//        $this->cacheTagIsCache();
        //处理所有电影下没有缓存的影片设置为缓存
//        db('vod')->where('is_cache', 0)->where(function ($query) {
//            $query->where('type_id', 1)->whereOr('type_id_1', 1);
//        })->update(['is_cache' => 1]);

    }

    /**
     * 缓存任务列表方法
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function getUpdateVodList()
    {
        selfDump(date('m-d H:i:s') . '开始获取待处理影片数据');
        //删除1个小时前完成的任务 保证数据库中数据均为1小时内
        \db('m3u8_job_bj')->where('status', 2)->whereTime('vod_time', '<=', '-1 hour')->delete();
        selfDump('删除一小时前完成的任务根据vod_time来判定 调试中  暂未开启' . db('m3u8_job_bj')->getLastSql());
        // 将要更新的片子进行处理，如果


        // 获取最近1小时要处理数据 更新时间相同则不处理
        $list = db('vod')->where('is_cache', 1)
            ->where('vod_play_from', 'like', '%bjm3u8%')
            ->whereTime('vod_time', '-1 hour')
            ->order('vod_time', 'asc')->order(
                'vod_id',
                'asc'
            )->field(
                'vod_id,vod_name,vod_time'
            )->select();
        selfDump('获取到需要处理的数据共计' . count($list) . '条');
        if (empty($list)) {
            selfDump('目前没有处理数据');
            return;
        }
        $time = time();
        foreach ($list as $key => $item) {
            // 不存在vod_id则添加
            // 任务未处理则更新更新时间
            // 任务
            //      更新时间相同则不添加
            //      处理完成，更新时间大于任务记录更新时间则添加
            //      处理中，更新时间不同添加

            selfDump('开始处理第' . ($key + 1) . ' 条数据');
            selfDump($item);
            $findJob = db('m3u8_job_bj')->where('vod_id', $item['vod_id'])->order('vod_time', 'desc')->find();
            selfDump(empty($findJob) ? '没有找到历史数据' : '找到历史数据', $findJob);
            if (empty($findJob) || ($item['vod_time'] > $findJob['vod_time'] && $findJob['status'] >= 1)) {
                if (empty($findJob)) {
                    selfDump($item['vod_id'] . '没有记录添加');
                } elseif ($findJob['status'] == 1) {
                    selfDump($item['vod_id'] . '任务处理中，更新时间较新，添加新任务');
                } elseif ($findJob['status'] == 2) {
                    selfDump($item['vod_id'] . '任务处理完成，更新时间较新，添加新任务');
                }
                //没有记录 或者 存在更新时间大于记录时间完成的处理中或者完成记录 则新增
                selfDump($item['vod_time'] . ' 任务添加' . $item['vod_id'] . ' <' . $item['vod_name'] . '>');
                db('m3u8_job_bj')->insert(
                    [
                        'vod_id' => $item['vod_id'],
                        'vod_time' => $item['vod_time'],
                        'time_added' => $time,
                        'status' => 0
                    ]
                );
            } elseif ($findJob['status'] == 0 && $item['vod_time'] > $findJob['vod_time']) {
                selfDump(
                    $findJob['id'] . ' jobId -' . $item['vod_time'] . '更新时间变更 ' . $item['vod_id'] . ' <' . $item['vod_name'] . '>'
                );
                db('m3u8_job_bj')->where('id', $findJob['id'])->update(
                    [
                        "vod_time" => $item['vod_time']
                    ]
                );
            } else {
                selfDump('不对任务做任何处理' . $item['vod_id'] . ' <' . $item['vod_name'] . '>');
            }
            selfDump('第' . ($key + 1) . ' 条数据处理结束');
        }
        selfDump('处理任务表数据结束');
    }

    public function dealUpdateVodList()
    {
        //循环得到20条数据
        for ($i = 0; $i < 100; $i++) {
            selfDump('执行影片缓存，本次为' . ($i + 1) . '部');
            $dealData = db('m3u8_job_bj')->where('status', 0)->order('vod_time', 'asc')->find();
            echo "<pre>";
            echo var_export($dealData, true);
            echo "</pre>";
            selfDump('获取到该条任务数据' . $dealData['id'] . ' vod_id:' . $dealData['vod_id']);
            selfDump($dealData);
            if (!empty($dealData)) {
                //设置状态处理中，设置失败的说明其他任务已处理
                $return = db('m3u8_job_bj')->where('id', $dealData['id'])->update(['status' => 1]);
                if ($return === 0) {
                    $i -= 1;
                    selfDump('id-' . $dealData['id'] . '-vod_id' . $dealData['vod_id'] . '当前数据已经被其他进程标记');
                    continue;
                }
                db('m3u8_job_bj')->where('id', $dealData['id'])->update(['time_started' => time()]);
                selfDump('任务数据可以被使用');
                //开始处理逻辑
                $returnData = $this->compareVodData($dealData);
                selfDump('得到处理数组 ', $returnData);

                if ($returnData !== null) {
                    //先删除 在增加 在更新
                    if (!empty($returnData['delete'])) {
                        $this->delteM3u8List($returnData['delete']);
                    }
                    if (!empty($returnData['add'])) {
                        $this->addM3u8List($returnData['add']);
                    }
                    if (!empty($returnData['update'])) {
                        $this->updateM3u8List($returnData['update']);
                    }
                    db('m3u8_job_bj')->where('id', $dealData['id'])->update(['status' => 2, 'time_finished' => time()]);
                } else {
                    $return = db('m3u8_job_bj')->where('id', $dealData['id'])->update(['status' => -1]);
                    selfDump('没有获取到数据，跳过本跳数据');
                }

            } else {
                selfDump('没有获取到数据，跳过执行下载缓存');
            }
            selfDump('本次为' . ($i + 1) . '部执行结束');
        }
        selfDump('循环执行结束！');
    }

    public function compareVodData($data)
    {
        //返回数据格式

        $jobArray = ['add' => [], 'delete' => [], 'update' => []];
        $time = time();
        //检查数据库中数据
        $cacheList = db('m3u8_cache_bj')->where('vod_id', $data['vod_id'])->order(
            'sort',
            'asc'
        )->select();
        selfDump('获取到缓存条目数量' . count($cacheList));


        $vodInfo = db('vod')->where('vod_id', $data['vod_id'])->field(
            'vod_id,vod_name,vod_play_from,vod_play_url'
        )->find();
        $vodSetting = db('m3u8_setting')->where('vod_id', $data['vod_id'])->find();
//        if (!empty($vodSetting)) {
//            $startIndex = $vodSetting['delete_start_index'];
//            $endIndex = $vodSetting['delete_end_index'];
//            $downloadNumber = $vodSetting['number'];
//        } else {
        $startIndex = 0;
        $endIndex = 0;
        $downloadNumber = $this->downloadTsNumbers;

//        }
        selfDump($vodInfo['vod_name'] . '数据比较开始');
        //拆分并取得相应的数据
        $playFroms = explode('$$$', $vodInfo['vod_play_from']);

        selfDump('得到原始播放源===', $playFroms);
        $playUrlArray = [];
        $fromIndex = array_search('bjm3u8', $playFroms);
        selfDump('当前获取到的播放源：' . $fromIndex);
        if ($fromIndex !== false) {
            $from = 'bjm3u8';
        } else {
            $from = '';
        }
        // 返回空数据
        if (empty($from)) {
            selfDump('没有找到制定缓存的资源');
            return null;
        }
        selfDump('找到播放源' . $from);
        $playUrlGroup = explode('$$$', $vodInfo['vod_play_url']);
        $playUrls = $playUrlGroup[$fromIndex];
        $playUrlsArray = explode('#', $playUrls);
        foreach ($playUrlsArray as $urlIndex => $playUrl) {
            list($key, $value) = explode('$', $playUrl);
            $playUrlArray[] = [
                'key' => trim($key),
                'value' => trim($value),
                'from' => $from,
                'vod_id' => $vodInfo['vod_id'],
                'vod_name' => $vodInfo['vod_name'],
                'time_added' => $time,
                'sort' => $urlIndex,
                'ts_offset' => $endIndex,
                'ts_number' => $downloadNumber,//10个ts
            ];
        }

        if (empty($cacheList)) {
            //删除本地缓存
            $cachePath1 = ROOT_PATH . 'upload/m3u8/' . $data['vod_id'];
            $this->delDirAndFile($cachePath1, true);
            $cachePath2 = ROOT_PATH . 'upload/m3u8s/' . $data['vod_id'];
            $this->delDirAndFile($cachePath2, true);
            //重新生成全部数据
            $jobArray['add'] = $playUrlArray;
        } elseif ($data['need_delete'] == 1) {
            if (!empty($cacheList)) {
                //现有的数据全部删除
                $jobArray['delete'] = $cacheList;
            }
            //新的数据全部增加
            $jobArray['add'] = $playUrlArray;
        } else {
            //得到新的播放m3u8数据 保持顺序
            $urlPlayUrlArray = array_column($playUrlArray, 'value');
            $cachePlayUrlArray = [];
            foreach ($cacheList as $cacheKey => $catchItem) {
                $cachePlayUrlArray[$catchItem['sort']] = $catchItem['value'];
                $cachePlayUrlArrayOld[$cacheKey] = $catchItem['value'];
            }
            selfDump('原始播放列表', $urlPlayUrlArray);
            selfDump('缓存的播放列表', $cachePlayUrlArray);
            //以cacheList为基准，求交集得到要更新的文件列表
            $updatedArray = array_intersect($cachePlayUrlArray, $urlPlayUrlArray);
            selfDump('得到交集 需要更新数组', $updatedArray);
            $needUpdateData = [];
            foreach ($updatedArray as $key => $updateItem) {
                //得到序号
                $urlPlayUrlIndex = array_search($updateItem, $urlPlayUrlArray);
                $urlPlayUrlDataInfo = $playUrlArray[$urlPlayUrlIndex];
//                    selfDump("urlPlayUrlDataInfo", $urlPlayUrlDataInfo);
                $cacheIndex = array_search($updateItem, $cachePlayUrlArrayOld);
                $cacheDataInfo = $cacheList[$cacheIndex];
//                    selfDump("cacheDataInfo", $cacheDataInfo);
                $changeData = [];
                if ($cacheDataInfo['sort'] !== $urlPlayUrlDataInfo['sort']) {
                    $changeData['sort'] = $urlPlayUrlDataInfo['sort'];
                }
                if ($cacheDataInfo['key'] !== $urlPlayUrlDataInfo['key']) {
                    $changeData['key'] = $urlPlayUrlDataInfo['key'];
                }
//                    selfDump('当前m3u8地址比对');
//                    selfDump($cacheDataInfo['value'] !== $urlPlayUrlDataInfo['value']);
                if ($cacheDataInfo['value'] !== $urlPlayUrlDataInfo['value']) {
                    $changeData['is_cache'] = 0;
                    $changeData['value'] = $urlPlayUrlDataInfo['value'];
                }
                if (!empty($changeData)) {
                    $changeData['id'] = $cacheDataInfo['id'];
                    $needUpdateData[] = $changeData;
                }
            }
            foreach ($cacheList as $cacheItem) {
                if ($cacheItem['is_cache'] == 0) {
                    $needUpdateData[] = $cacheItem;
                }
            }
            $jobArray['update'] = $needUpdateData;
            //以cacheList为基准，求差集得到要删除的文件列表
            $deleteArray = array_diff($cachePlayUrlArray, $urlPlayUrlArray);
            selfDump('得到差集，需要删除数组', $deleteArray);
            $needDeleteData = [];
            foreach ($deleteArray as $key => $deleteItem) {
                $cacheIndex = array_search($deleteItem, $cachePlayUrlArrayOld);
                $cacheDataInfo = $cacheList[$cacheIndex];
//                    selfDump($cacheDataInfo);
                $needDeleteData[] = $cacheDataInfo;
            }
            $jobArray['delete'] = $needDeleteData;
            //以新的播放m3u8数据为基准，求差集得到要删除的文件列表
            $addArray = array_diff($urlPlayUrlArray, $cachePlayUrlArray);
            selfDump('得到差集，需要增加数组', $addArray);
            $needAddData = [];
            foreach ($addArray as $key => $addItem) {
                $urlPlayUrlIndex = array_search($addItem, $urlPlayUrlArray);
                $urlPlayUrlDataInfo = $playUrlArray[$urlPlayUrlIndex];
                $needAddData[] = $urlPlayUrlDataInfo;
            }

            $jobArray['add'] = $needAddData;
        }
        return $jobArray;
    }

    public function addM3u8List($list)
    {
        foreach ($list as $item) {
            selfDump($item);
            $cachePath = $this->cachePath;//相对路径
            $this->checkAndMakeDir(ROOT_PATH . $cachePath);
            $itemDbDataId = db('m3u8_cache_bj')->insertGetId($item);
            $itemDbData = db('m3u8_cache_bj')->where('id', $itemDbDataId)->find();
            $ossM3u8Path = $item['vod_id'] . '/' . $itemDbData['sort'] . '.m3u8';//相对路径
            $m3u8FilePath = $cachePath . '/' . $ossM3u8Path;//相对路径
//            $return = $this->downLoadM3u8($cachePath, $itemDbData, $m3u8FilePath, $ossM3u8Path);
            $return=true;
            selfDump([
                'is_cache' => 1,
                'cache_value' => $this->m3u8Url . $this->ossPathPre . $ossM3u8Path,
                'path_oss' => $this->ossPathPre . $ossM3u8Path,
                'update_time' => time(),
                'path' => $m3u8FilePath
            ]);
            if ($return !== false) {
                db('m3u8_cache_bj')->where('id', $itemDbData['id'])->update(
                    [
                        'is_cache' => 1,
//                        'cache_value' => $this->m3u8Url . $this->ossPathPre . $ossM3u8Path,
                        'cache_value' => null,
//                        'path_oss' => $this->ossPathPre . $ossM3u8Path,
                        'path_oss' => null,
                        'update_time' => time(),
//                        'path' => $m3u8FilePath,
                        'path' => null,
                        'try_times' => $itemDbData['try_times'] + 1
                    ]
                );
                file_get_contents("http://www.shengtangzhongguo.com/app.php/vod/deleteDetailCache/vod_id/".$itemDbData['vod_id']);
                selfDump('m3u8文件添加成功,缓存已经删除 '."http://www.shengtangzhongguo.com/app.php/vod/deleteDetailCache/vod_id/".$itemDbData['vod_id']);
            } else {
                db('m3u8_cache_bj')->where('id', $itemDbData['id'])->update(
                    [
                        'is_cache' => -1,
                        'try_times' => $itemDbData['try_times'] + 1
                    ]
                );
                selfDump('m3u8文件添加失败');
            }
            selfDump($item);

        }
    }

    public function delteM3u8List($list)
    {
        foreach ($list as $item) {
            //删除本地目录
            if (!empty($item['path'])) {
                $m3u8FilePath = ROOT_PATH . $item['path'];
                $ossM3u8FilePath = $item['path_oss'];
                $tsPath = dirname($m3u8FilePath) . '/' . $item['sort'];
                $ossTsPath = dirname($ossM3u8FilePath) . '/' . $item['sort'];
                if (!empty($item['path'])) {
                    $this->deleteM3u8($m3u8FilePath, $ossM3u8FilePath);
                    $this->deleteTs($tsPath, $ossTsPath);
                }
            }
            db('m3u8_cache_bj')->where('id', $item['id'])->delete();
            selfDump($item);
            selfDump('待删除缓存数据库删除成功');
        }
    }

    public function updateM3u8List($list, $falseNumber = -1)
    {
        foreach ($list as $item) {
            selfDump('得到要更新的数据', $item);
            $itemDbData = db('m3u8_cache_bj')->where('id', $item['id'])->find();
            if (isset($item['is_cache']) && $item['is_cache'] < 1) {
                if (!empty($itemDbData['path'])) {
                    selfDump('m3u8更新数据需要重新缓存' . $itemDbData['path_oss']);
                    $ossM3u8Path =  $item['vod_id'] . '/' . $itemDbData['sort'] . '.m3u8';//相对路径
                    $m3u8FilePath = $itemDbData['path'];//相对路径
                    //先删除原来的ts文件
                    selfDump('先删除原来的文件');
                    selfDump('原来的路径' . $itemDbData['path']);
//                    $this->deleteTs(
//                        ROOT_PATH . dirname($itemDbData['path']) . '/' . $itemDbData['sort'],
//                        dirname($itemDbData['path_oss']) . '/' . $itemDbData['sort']
//                    );
                } else {
                    selfDump('当前缓存并没有生成,将直接生成缓存');
                    $ossM3u8Path = $item['vod_id'] . '/' . $itemDbData['sort'] . '.m3u8';//相对路径
                    $m3u8FilePath = $this->cachePath . '/' . $ossM3u8Path;//相对路径
                    $itemDbData['path'] = $m3u8FilePath;
                    $itemDbData['path_oss'] = $this->ossPathPre . $ossM3u8Path;
                    $itemDbData['cache_value'] = $this->m3u8Url . $this->ossPathPre . $ossM3u8Path;
                }

//                $return = $this->downLoadM3u8($this->cachePath, $itemDbData, $m3u8FilePath, $ossM3u8Path);
                $return = true;
                unset($item['is_cache']);
                if ($return) {
                    selfDump('下载m3u8成功！ 设置缓存状态1！');
                    $itemDbData['is_cache'] = 1;
                    $itemDbData['update_time'] = time();
                    $itemDbData['try_times'] = $itemDbData['try_times'] + 1;

                    //不缓存
                    $itemDbData['path'] = null;
                    $itemDbData['path_oss'] = null;
                    $itemDbData['cache_value'] = null;
                    selfDump($itemDbData);
                } else {
                    $itemDbData['path'] = null;
                    $itemDbData['path_oss'] = null;
                    $itemDbData['cache_value'] = null;
                    $itemDbData['is_cache'] = $falseNumber;
                    $itemDbData['try_times'] = $itemDbData['try_times'] + 1;
                    selfDump('下载m3u8出错了！');
                }
            }

            unset($item['id']);
            selfDump('剩余要修改的信息', $item);
            if (!empty($item)) {
                db('m3u8_cache_bj')->where('id', $itemDbData['id'])->update($itemDbData);
                selfDump('更新数据sql==' . db('m3u8_cache_bj')->getLastSql());
                selfDump('当前falseNumber' . $falseNumber);
                selfDump('当前is_cache' . $itemDbData['is_cache']);

                if ($falseNumber == -2 && $itemDbData['is_cache'] < 0) {
                    if ($itemDbData['try_times'] > 4) {
                        $otherMessage = ' 本剧集已经5次尝试，仍无法处理，请手动管理该资源！';
                    } else {
                        $otherMessage = '';
                    }
                    $return = sendDingding(
                        'vod_id=>' . $itemDbData['vod_id'] . ' - ' . $itemDbData['vod_name'] . '[' . $itemDbData['key'] . ']-- 重新下载成功 -- ' . $itemDbData['value'] . "\n" . $otherMessage,
                        'bjoss',
                        ["17705336300"]
                    );
                    selfDump('丁丁返回消息', $return);
                }
            } else {
                selfDump('本条数据没有什么需要更新的');
            }
        }
    }

    protected function downloadM3u8($cachePath, $itemDbData, $m3u8FilePath, $ossM3u8Path)
    {

        $m3u8DataArray = $this->getM3u8DataArray($itemDbData['value'],$itemDbData,1);
        if($m3u8DataArray===false){
            return false;
        }
        selfDump('解析m3u8文件得到的内容是',$m3u8DataArray);
        $m3u8contentArray = $m3u8DataArray['m3u8contentArray'];
        $baseUrlArray = $m3u8DataArray['baseUrlArray'];

        $offsetIndex = 0;
        $duration = 0;
        selfDump('要跳过的时间' . $this->offsetDuration);
        $startIndex = -1;
        foreach ($m3u8contentArray as $tsKey => $tsItem) {
            selfDump($tsKey, $tsItem);
            if ($startIndex === -1 && strpos($tsItem, '#EXTINF') === 0) {
                $startIndex = $tsKey;
            }
//            selfDump('当前序号 ', $startIndex . "_" . $tsKey . "_offset_" . $offsetIndex);
            if ((strpos($tsItem, '.ts') > 0 || strpos($tsItem, '.png') > 0) && (strpos($tsItem, '#') === false)) {
//                selfDump('====d=d=d==d=d=d jinru ');
                if ($duration <= $this->offsetDuration) {
//                    selfDump($duration .'当前小于10s 要删除的 序号' . ($offsetIndex + 1));
//                    selfDump('要删除 key' . $tsKey." "." tsitem ".$tsItem);
//                    selfDump('要删除 ' . ($tsKey - 1)." tsitem ".$m3u8contentArray[$tsKey - 1]);
                    unset($m3u8contentArray[$tsKey]);
                    unset($m3u8contentArray[$tsKey - 1]);
                    $offsetIndex++;
                } else {
                    if(strpos($tsItem,'/')===0) {
//                        selfDump('tsItem路径 以/开始'.$tsItem);
                        $tsItem = $baseUrlArray[0]."/".$baseUrlArray[1]."/".$baseUrlArray[2]  . $tsItem;

                    }elseif(strpos($tsItem,'http')!==0){
//                        selfDump('tsItem路径 以http开始'.$tsItem);
                        $tsItem = join('/', $baseUrlArray) . '/' . $tsItem;
                    }
                    if($duration>10 && $offsetIndex===0){
//                        selfDump($duration .'当前大于10s 但是没有删除过ts  要删除的 序号' . ($offsetIndex + 1));
//                        selfDump('要删除 key' . $tsKey." "." tsitem ".$tsItem);
//                        selfDump('要删除 ' . ($tsKey - 1)." tsitem ".$m3u8contentArray[$tsKey - 1]);
                        unset($m3u8contentArray[$tsKey]);
                        unset($m3u8contentArray[$tsKey - 1]);
                        $offsetIndex++;
                    }else {
//                        selfDump($duration . "当前大于10s 不需要删除" . $tsKey . "  " . $tsItem);
                        $m3u8contentArray[$tsKey] = $tsItem;
                    }
                }

            }else if(strpos($tsItem,'#EXTINF')===0){
                $time =str_replace(['#EXTINF:',','],['',''],$tsItem);
                $duration += $time;
//                $m3u8contentArray[$tsKey] = "当前ts播放完毕是[ ".$duration.' ]秒';
            }
        }
//                selfDump('m3u8数据为',$m3u8contentArray);
        //保存m3u8文件

//            go(function ()use($m3u8contentArray, $m3u8FilePath, $ossM3u8Path){
        return $this->saveM3u8(join("\n", $m3u8contentArray), $m3u8FilePath, $ossM3u8Path);
//            });
    }


    public function getM3u8DataArray($targetM3u8Url,$itemDbData,$fileNum){
        selfDump('$targetM3u8Url==' . $targetM3u8Url);
        $targetM3u8Url = str_replace('\\','/',$targetM3u8Url);
        if (!$this->checkMeu8Url($targetM3u8Url)) {
            sendDingding(
                'vod_id=>' . $itemDbData['vod_id'] . ' - ' . $itemDbData['vod_name'] . '[' . $itemDbData['key'] . ']--第'.$fileNum.'个m3u8文件路径出错-- ' . $targetM3u8Url,
                'bjoss'
            );
            selfDump('vod_id=>' . $itemDbData['vod_id'] . ' - ' . $itemDbData['vod_name'] . '[' . $itemDbData['key'] . ']--第'.$fileNum.'个m3u8文件路径出错-- ' . $targetM3u8Url);
            return false;
        }
        $downLoadFirstM3u8 = 0;
        while ($downLoadFirstM3u8 < 5) {
            selfDump('开始第' . ($downLoadFirstM3u8 + 1) . '次获取 第'.$fileNum.'个m3u8文件');
            $m3u8content = fget_contents($targetM3u8Url);
            if ($m3u8content !== false) {
                break;
            } else {
                if ($downLoadFirstM3u8 == 4) {
                    sendDingding(
                        'vod_id=>' . $itemDbData['vod_id'] . ' - ' . $itemDbData['vod_name'] . '[' . $itemDbData['key'] . ']--下载第'.$fileNum.'个m3u8文件出错-- ' . $itemDbData['value'],
                        'bjoss'
                    );
                    selfDump('vod_id=>' . $itemDbData['vod_id'] . ' - ' . $itemDbData['vod_name'] . '[' . $itemDbData['key'] . ']--下载第'.$fileNum.'个m3u8文件出错-- ' . $itemDbData['value']);
                    return false;
                }
            }
            $downLoadFirstM3u8++;
        }


        selfDump('处理第'.$fileNum.'个m3u8内容信息');
        if(strpos($m3u8content,'.m3u8')>0){
            selfDump("内嵌了一个m3u8——".$fileNum++);
            $urlArray = explode('/', $targetM3u8Url);
            array_pop($urlArray);
            selfDump(($fileNum-1).'-m3u8文件数组',$urlArray);
            $m3u8contentArray = explode("\n", $m3u8content);
            $m3u8contentArray = array_filter($m3u8contentArray);
            $targetM3u8Url = array_pop($m3u8contentArray);
            if(strpos($targetM3u8Url,'/')===0) {
                $targetM3u8Url = $urlArray[0]."/".$urlArray[1]."/".$urlArray[2] . $targetM3u8Url;
            }elseif(strpos($targetM3u8Url,'http')!==0){
                $targetM3u8Url = join('/', $urlArray) . '/' . $targetM3u8Url;
            }
            selfDump('内嵌的m3u8地址是'.$targetM3u8Url);
            return $this->getM3u8DataArray($targetM3u8Url,$itemDbData,$fileNum);
        }else{
            $baseUrlArray = explode('/', $targetM3u8Url);
            selfDump($baseUrlArray);
            array_pop($baseUrlArray);
            $baseUrl = join('/', $baseUrlArray);
            selfDump('得到最终 baseUrl :' . $baseUrl);
            selfDump($m3u8content);
            $m3u8contentArray = explode("\n", $m3u8content);
            $m3u8contentArray = array_filter($m3u8contentArray);
            if(empty($m3u8contentArray)){
                sendDingding(
                    'vod_id=>' . $itemDbData['vod_id'] . ' - ' . $itemDbData['vod_name'] . '[' . $itemDbData['key'] . ']--第'.$fileNum.'个m3u8文件 处理 出错-- ' . $itemDbData['value'],
                    'bjoss'
                );
                selfDump('vod_id=>' . $itemDbData['vod_id'] . ' - ' . $itemDbData['vod_name'] . '[' . $itemDbData['key'] . ']--第'.$fileNum.'个m3u8文件内容处理出错-- ' . $itemDbData['value']);
                return false;
            }
            return ['baseUrlArray'=>$baseUrlArray,'m3u8contentArray'=>$m3u8contentArray];
        }
    }

    /**
     * 下载ts文件并上传到oss
     * @param $tsUrl
     * @param $tsPath
     * @param $ossTsPath
     */
    protected function downLoadTs($tsUrl, $tsPath, $ossTsPath)
    {
        $tsContent = file_get_contents($tsUrl);
        $uploadTims = 0;
        $this->checkAndMakeDir(ROOT_PATH . $tsPath);
        file_put_contents(ROOT_PATH . $tsPath, $tsContent);
        do {
            if ($uploadTims > 2) {
                selfDump($ossTsPath . '--TS上传文件出错-');
                sendDingding(
                    $ossTsPath . '--TS上传文件出错-',
                    'bjoss'
                );
                break;
            }
            selfDump('正在进行第' . ($uploadTims + 1) . '次上传' . $ossTsPath);
            $uploadResult = $this->uploadToOss($ossTsPath, $tsContent);
            $uploadTims++;
        } while (!$uploadResult);
        selfDump($ossTsPath . '--TS上传文件成功-');
    }

    protected function saveM3u8($m3u8Content, $m3u8FilePath, $ossM3u8Path)
    {
        $this->checkAndMakeDir(ROOT_PATH . $m3u8FilePath);
        file_put_contents($m3u8FilePath, $m3u8Content);
        do {
            if ($uploadTims > 2) {
                sendDingding(
                    $ossM3u8Path . '--上传m3u8文件出错-',
                    'bjoss'
                );
                selfDump($ossM3u8Path . '--上传m3u8文件出错-');
                return false;
                break;
            }
            selfDump('正在进行第' . ($uploadTims + 1) . '次上传' . $ossM3u8Path);
            $uploadResult = $this->uploadToOss($ossM3u8Path, $m3u8Content);
            $uploadTims++;
        } while (!$uploadResult);
        return true;
    }

    public function uploadToOss($ossTsPath, $tsContent, $ossPathPre = '')
    {
        if (empty($ossPathPre)) {
            $ossPathPre = $this->ossPathPre;
        }
        if ($this->canUploadToOss) {
            selfdump('开始处理文件上传' . $ossTsPath);
            try {
                $this->ossClient->putObject($this->bucket, $ossPathPre . $ossTsPath, $tsContent);
            } catch (OssException $e) {
                selfDump($e->getErrorMessage(), $e->getMessage());
                return false;
            }
            selfDump('文件上传成功！');
        } else {
            selfdump('不需要文件上传' . $ossTsPath);
        }
        return true;
    }

    public function deleteM3u8($m3u8path, $ossM3u8Path)
    {
        //删除本地文件
        $this->delDirAndFile($m3u8path);
        if ($this->canUploadToOss) {
            dump('需要删除oss文件' . $m3u8path);
            //删除m3u8
            try {
                $return = $this->ossClient->deleteObject($this->bucket, $this->ossPathPre . $ossM3u8Path);
            } catch (OssException $e) {
                sendDingding($ossM3u8Path . ' 删除失败', 'bjoss');
            }
            selfDump('删除oss文件成功' . $m3u8path);
        } else {
            selfDump('无需删除oss文件' . $m3u8path);
        }
    }

    public function deleteTs($tsPath, $ossTsPath)
    {
        //TODO 先删除本地
        $this->delDirAndFile($tsPath, true);

        if ($this->canUploadToOss) {
            dump('需要删除TS文件');
            $ossTsPath = trim($ossTsPath, '/') . '/';
            try {
                $prefix = $ossTsPath;
                $delimiter = '/';
                $nextMarker = '';
                $maxkeys = 100;
                $options = [
                    'delimiter' => $delimiter,
                    'prefix' => $prefix,
                    'max-keys' => $maxkeys,
                    'marker' => $nextMarker,
                ];
                $listObjectInfo = $this->ossClient->listObjects($this->bucket, $options);
            } catch (OssException $e) {
                sendDingding('获取' . $ossTsPath . '下所有文件时失败！' . $e->getMessage(), 'bjoss');
                return false;
            }
            $objects = [];
            $listObject = $listObjectInfo->getObjectList();
            foreach ($listObject as $objectInfo) {
                $objects[] = $objectInfo->getKey();
            }
            selfDump('获取到oss上的文件有', $objects);
            if (!empty($objects)) {
                try {
                    $this->ossClient->deleteObjects($this->bucket, $objects);
                    $this->ossClient->deleteObject($this->bucket, $this->ossPathPre . $ossTsPath);
                } catch (OssException $e) {
                    sendDingding('批量删除 oss 目录' . $tsPath . '下文件，失败' . $e->getMessage(), 'bjoss');
                }
                selfDump('删除oss上TS缓存成功');
            } else {
                selfDump('oss 缓存数据为空，无需删除');
            }
        } else {
            selfDump('无需删除oss上的TS缓存');
        }
        return true;
    }

    protected function checkAndMakeDir($path)
    {
//            selfDump(' 不再保存数据到本地 正在检查'.$path);
//            return ;
        selfDump('正在检查' . $path);
        $path = dirname($path);
        if (!file_exists($path)) {
            selfDump('即将创建' . $path);
            $reutrn = mkdir($path, 0777, true);
            selfDump('创建结果', $reutrn);
        } else {
            selfDump('存在目录');
        }
    }

    public function delDirAndFile($path, $delDir = false)
    {
        if (empty($path) || (trim($path, '/') . '/') === ROOT_PATH || $path == '/') {
            selfDump('path路径有误,无法删除 当前path是' . $path);
            return false;
        }
        selfDump('要删除的路径 ', $path);

        if (is_array($path)) {
            foreach ($path as $subPath) {
                $this->delDirAndFile($subPath, $delDir);
            }
        }
        if (is_dir($path)) {
            selfDump('要删除的路径 ' . $path);
            $handle = opendir($path);
            if ($handle) {
                while (false !== ($item = readdir($handle))) {
                    if ($item != "." && $item != "..") {
                        is_dir("$path/$item") ? $this->delDirAndFile("$path/$item", $delDir) : unlink(
                            "$path/$item"
                        );
                    }
                }
                closedir($handle);
                if ($delDir) {
                    return rmdir($path);
                }
            }
        } else {
            if (file_exists($path)) {
                return unlink($path);
            } else {
                return false;
            }
        }
    }

    /**
     * 单独生成一个缓存
     *
     *  php app.php bjm3u8/dosingle/vod_id/
     * @param $vod_id
     * @return \think\response\Json
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \think\Exception
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public function doSingle($vod_id)
    {
        ignore_user_abort(true);
        set_time_limit(0);
        $vodInfo = db('vod')->where('vod_id', $vod_id)->find();
        if (empty($vodInfo)) {
            return json(['code' => 0, 'msg' => '数据查询有误！']);
        }
        $dealData = db('m3u8_job_bj')->where('vod_id', $vod_id)->find();
        selfDump($dealData);
        if (!empty($dealData) && $dealData['status'] == 0) {
            $return = db('m3u8_job_bj')->where('id', $dealData['id'])->update(['status' => 1]);
            if ($return == 0) {
                return json(['code' => 0, 'msg' => '数据正在处理中']);
            }
        } elseif (!empty($dealData) && $dealData['status'] == 1) {
            return json(['code' => 0, 'msg' => '数据正在处理中']);
        } else {
            $dealData = [
                'vod_id' => $vod_id,
                'time_added' => time(),
                'vod_name' => $vodInfo['vod_name'],
                'vod_time' => time(),
                'time_started' => 0,
                'time_finished' => 0,
                'status' => 1,
            ];

            $dealData['id'] = db('m3u8_job_bj')->insertGetId($dealData);
        }
        $dealData['vod_name'] = $vodInfo['vod_name'];
        selfDump($dealData);
        $returnData = $this->compareVodData($dealData);
        if ($returnData !== null) {
            selfDump(
                '需要处理的数据 --- ' . $dealData['id'] . ' vod_id:' . $dealData['vod_id'] . ' vod_name:' . $dealData['vod_name'],
                $returnData
            );
            //先删除在增加 再更新
            if (!empty($returnData['delete'])) {
                $this->delteM3u8List($returnData['delete']);
            }
            if (!empty($returnData['add'])) {
                $this->addM3u8List($returnData['add']);
            }
            if (!empty($returnData['update'])) {
                $this->updateM3u8List($returnData['update']);
            }
            db('m3u8_job_bj')->where('id', $dealData['id'])->update(['status' => 2, 'time_finished' => time()]);
            selfDump('数据处理结束' . $dealData['id'] . ' vod_id:' . $dealData['vod_id'] . ' vod_name:' . $dealData['vod_name']);
            sendDingding(
                $dealData['id'] . ' vod_id:' . $dealData['vod_id'] . ' vod_name:' . $dealData['vod_name'] . '缓存结束',
                'bjoss'
            );
        } else {
            db('m3u8_job_bj')->where('id', $dealData['id'])->update(['status' => -1]);
            sendDingding(
                $dealData['id'] . ' vod_id:' . $dealData['vod_id'] . ' vod_name:' . $dealData['vod_name'] . '缓存失败，没有bjm3u8源',
                'bjoss'
            );

        }
    }

    /**
     * 将所有标记了 缓存的 加入到缓存记录表准备生成缓存
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \think\Exception
     * @throws \think\db\exception\BindParamException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public function cacheTagIsCache()
    {
//        db('vod')->where('is_cache', 0)->where(function ($query) {
//            $query->where('type_id', 1)->whereOr('type_id_1', 1);
//        })->update(['is_cache' => 1]);

        $sql = 'SELECT v.vod_id,v.vod_name,v.vod_time from mac_vod as v LEFT JOIN mac_m3u8_cache_bj as mc on mc.vod_id = v.vod_id WHERE mc.vod_id is null and v.is_cache >=0 and  v.vod_play_from like "%bjm3u8%"';
        $list = db()->query($sql);
        $time = time();
        foreach ($list as $key => $item) {
            // 不存在vod_id则添加
            // 任务未处理则更新更新时间
            // 任务
            //      更新时间相同则不添加
            //      处理完成，更新时间大于任务记录更新时间则添加
            //      处理中，更新时间不同添加

            selfDump('开始处理第' . ($key + 1) . ' 条数据');
            selfDump($item);
            $findJob = db('m3u8_job_bj')->where('vod_id', $item['vod_id'])->order('vod_time', 'desc')->find();
            selfDump(empty($findJob) ? '没有找到历史数据' : '找到历史数据', $findJob);
            if (empty($findJob) || ($item['vod_time'] > $findJob['vod_time'] && $findJob['status'] >= 1)) {
                if (empty($findJob)) {
                    selfDump($item['vod_id'] . '没有记录添加');
                } elseif ($findJob['status'] == 1) {
                    selfDump($item['vod_id'] . '任务处理中，更新时间较新，添加新任务');
                } elseif ($findJob['status'] == 2) {
                    selfDump($item['vod_id'] . '任务处理完成，更新时间较新，添加新任务');
                }
                //没有记录 或者 存在更新时间大于记录时间完成的处理中或者完成记录 则新增
                selfDump($item['vod_time'] . ' 任务添加' . $item['vod_id'] . ' <' . $item['vod_name'] . '>');
                db('m3u8_job_bj')->insert(
                    [
                        'vod_id' => $item['vod_id'],
                        'vod_time' => $item['vod_time'],
                        'time_added' => $time,
                        'status' => 0
                    ]
                );
            } elseif ($findJob['status'] == 0 && $item['vod_time'] > $findJob['vod_time']) {
                selfDump(
                    $findJob['id'] . ' jobId -' . $item['vod_time'] . '更新时间变更 ' . $item['vod_id'] . ' <' . $item['vod_name'] . '>'
                );
                db('m3u8_job_bj')->where('id', $findJob['id'])->update(
                    [
                        "vod_time" => $item['vod_time']
                    ]
                );
            } else {
                selfDump('不对任务做任何处理' . $item['vod_id'] . ' <' . $item['vod_name'] . '>');
            }
            selfDump('第' . ($key + 1) . ' 条数据处理结束');
        }
    }

    public function checkMeu8Url($m3u8Url)
    {
        $arr = explode('.m3u8', $m3u8Url);
        $count = count($arr);
        if ($arr[$count - 1] == "") {
            return true;
        } else {
            return false;
        }
    }


    public function reDealM3u8Cache()
    {
        global $argv;
        if (intval($argv[2]) > 0) {
            $page = intval($argv[2]);
        } else {
            $page = 0;
        }
//        dump($page);
        $list = db('m3u8_cache_bj')->where('is_cache', '<', 0)->where('try_times', '<', 5)->order('id', 'asc')->limit($page * 1, 100)->select();
        selfDump($list);
        $this->updateM3u8List($list, -2);
        sleep(10);

    }


    public function reCacheM3u8Batch(){
        $vodIds = db('m3u8_cache_bj')->where('id','<=',16762)->where('is_cache',1)->where('vod_id','>=',39366)->group('vod_id')->order('vod_id','asc')->column('vod_id');
//        dump(db('m3u8_cache_bj')->getLastSql());exit;
        selfDump('总共有'.count($vodIds).'影视需要处理');
        foreach ($vodIds as $index=>$vodId){
            selfDump('处理第'.$index.'条数据');
            $this->reCacheM3u8Sigle($vodId);
            selfDump('结束处理第'.$index.'条数据');
            file_put_contents('./vod_id.txt',$vodId);
        }
    }

    protected function reCacheM3u8Sigle($vod_id){
        $list = db('m3u8_cache_bj')->where('vod_id',$vod_id)->where('is_cache',1)->order('sort','asc')->select();
        foreach ($list as &$item){
                $item['is_cache'] = 0;
        }
        $this->updateM3u8List( $list,-1);
    }

    public function deleteMovieType(){
        $ids = db('m3u8_cache_bj')->alias('mcbj')->join('vod v','v.vod_id = mcbj.vod_id')->where(['v.type_id|v.type_id_1'=>1])->where('mcbj.is_cache','<',0)->column('mcbj.id');
//        dump(db('m3u8_cache_bj')->getLastSql());
        db('m3u8_cache_bj')->whereIn('id',$ids)->delete();
    }



    public function  deleteRepeatJuji(){
        $sql = "SELECT vod_id,sort,vod_name,`key`,count(sort) as num FROM mac_m3u8_cache_bj GROUP BY vod_id ,sort  HAVING COUNT(sort) >1  ORDER BY COUNT(sort) desc";

        $list = db('m3u8_cache_bj')->query($sql);
        $deleteIds=[];
        foreach ($list as $item){
            $bjcacheInfos = db('m3u8_cache_bj')->where('vod_id',$item['vod_id'])->where('sort',$item['sort'])->select();
            $count = count($bjcacheInfos);
            selfDump('发现'.$item['vod_id'].' '.$item['vod_name'].' '.$item['sort'] .' '.$item['key'] .'共有'.$count );
            if($count>1) {
                for ($i = 0; $i < $count - 1; $i++) {
                    selfDump($i);
                    $deleteIds[]=$bjcacheInfos[$i]['id'];
                }
            }else{
                selfDump('未能发现'.$item['vod_id'].' '.$item['vod_name'].' '.$item['sort'] .' '.$item['key'] .'多余数据');
            }
        }
        selfDump($deleteIds);
        selfDump('共计数据有'.count($deleteIds));
        $return = db('m3u8_cache_bj')->whereIn('id',$deleteIds)->delete();
        selfDump('共计删除'.$return.'跳数据');
    }
}